home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-03-15 | 73.9 KB | 2,172 lines | [TEXT/gamI] |
- ;==============================================================================
-
- ; file: "front.scm"
-
- ;------------------------------------------------------------------------------
- ;
- ; Front-end of GAMBIT compiler
- ;
- ;------------------------------------------------------------------------------
-
- ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ;
- ; The file compiler:
- ; -----------------
-
- ; sample use:
- ;
- ; (cf "tak" 'M68000) -- compile 'tak.scm' for M68000 target
- ; (cf "tak" 'M68000 'VERBOSE) -- produce compiler trace
- ; (cf "tak" 'M68000 'REPORT) -- show usage of global variables
- ; (cf "tak" 'M68000 'PVM) -- write PVM code on 'tak.pvm'
- ; (cf "tak" 'M68000 'DEBUG) -- generate code with debugging info
- ; (cf "tak" 'M68000 'EXPANSION) -- show code after source-to-source transform
- ; (cf "tak" 'M68000 'ASM 'STATS) -- various back-end options
-
- (define (cf source target-name . opts)
-
- (let ((module-name (file-name (file-root source)))
- (info-port (if (memq 'VERBOSE opts) (current-output-port) #f))
- (program
- (append (list BEGIN-sym)
- program-prefix
- (list (list **INCLUDE-sym source))
- program-suffix)))
-
- (let ((result (compile-program program
- target-name
- opts
- module-name
- (file-root source)
- info-port)))
-
- (if (and info-port (not (eq? info-port (current-output-port))))
- (close-output-port info-port))
-
- result)))
-
- (define program-prefix #f)
- (set! program-prefix '())
-
- (define program-suffix #f)
- (set! program-suffix '())
-
- ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ;
- ; The expression compiler:
- ; -----------------------
-
- ; sample use:
- ;
- ; (ce '(+ 2 3) 'M68000) -- compile the expression (+ 2 3)
-
- (define (ce expr target-name . opts)
-
- (let ((info-port (if (memq 'VERBOSE opts) (current-output-port) #f)))
-
- (let ((result (compile-program expr
- target-name
- opts
- "#"
- "#"
- info-port)))
-
- (if (and info-port (not (eq? info-port (current-output-port))))
- (close-output-port info-port))
-
- result)))
-
- ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ;
- ; The program compiler:
- ; --------------------
-
- (define (compile-program program target-name opts module-name dest info-port)
-
- (define (compiler-body)
-
- (scheme-global-var-set!
- (scheme-global-var (string->canonical-symbol "##COMPILATION-OPTIONS"))
- opts)
-
- (ptree.begin! info-port)
- (virtual.begin!)
- (select-target! target-name info-port)
-
- (parse-program
- (list (expression->source program #f))
- (make-global-environment)
- (lambda (lst env)
-
- (let ((parsed-program
- (map (lambda (x) (normalize-parse-tree (car x) (cdr x))) lst)))
-
- (if (memq 'EXPANSION opts)
- (let ((port (current-output-port)))
- (display "Expansion:" port)
- (newline port)
- (let loop ((l parsed-program))
- (if (pair? l)
- (let ((ptree (car l)))
- (pp-expression (parse-tree->expression ptree) port)
- (loop (cdr l)))))
- (newline port)))
-
- (let ((module-init-proc
- (compile-parsed-program module-name parsed-program env info-port)))
-
- (if (memq 'REPORT opts)
- (generate-report env))
-
- (if (memq 'PVM opts)
- (let ((pvm-port (open-output-file (string-append dest ".pvm"))))
- (virtual.dump module-init-proc pvm-port)
- (close-output-port pvm-port)))
-
- (target.dump module-init-proc dest opts)))))
-
- (unselect-target!)
- (virtual.end!)
- (ptree.end!)
-
- #t)
-
- (let ((successful (with-exception-handling compiler-body)))
-
- (if info-port
- (if successful
- (begin
- (display "Compilation finished." info-port)
- (newline info-port))
- (begin
- (display "Compilation terminated abnormally." info-port)
- (newline info-port))))
-
- successful))
-
- ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ;
- ; Report generation:
-
- (define (generate-report env)
- (let ((vars (sort-list (env-global-variables env)
- (lambda (x y)
- (string<? (symbol->string (var-name x))
- (symbol->string (var-name y))))))
- (decl (env-declarations env)))
-
- (define (report title pred? vars wrote-something?)
- (if (pair? vars)
- (let ((var (car vars)))
- (if (pred? var)
- (begin
- (if (not wrote-something?)
- (begin
- (display " ")
- (display title)
- (newline)))
- (let loop1 ((l (var-refs var)) (r? #f) (c? #f))
- (if (pair? l)
- (let* ((x (car l))
- (y (node-parent x)))
- (if (and y (app? y) (eq? x (app-oper y)))
- (loop1 (cdr l) r? #t)
- (loop1 (cdr l) #t c?)))
- (let loop2 ((l (var-sets var)) (d? #f) (a? #f))
- (if (pair? l)
- (if (set? (car l))
- (loop2 (cdr l) d? #t)
- (loop2 (cdr l) #t a?))
- (begin
- (display " [")
- (if d? (display "D") (display " "))
- (if a? (display "A") (display " "))
- (if r? (display "R") (display " "))
- (if c? (display "C") (display " "))
- (display "] ")
- (display (var-name var)) (newline))))))
- (report title pred? (cdr vars) #t))
- (cons (car vars) (report title pred? (cdr vars) wrote-something?))))
- (begin
- (if wrote-something? (newline))
- '())))
-
- (display "Global variable usage:") (newline)
- (newline)
-
- (report "OTHERS"
- (lambda (x) #t)
- (report "EXTENDED"
- (lambda (x) (target.prim-info (var-name x)))
- (report "STANDARD"
- (lambda (x) (standard-procedure (var-name x) decl))
- vars
- #f)
- #f)
- #f)))
-
- ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- (define (compile-parsed-program module-name program env info-port)
-
- (if info-port
- (display "Compiling:" info-port))
-
- (set! trace-indentation 0)
-
- (set! *bbs* (make-bbs))
- (set! *global-env* env)
-
- (set! proc-tree '())
- (set! proc-queue '())
- (set! constant-vars '())
- (set! known-procs '())
-
- (restore-context
- (make-context 0 '() (list ret-var) '() (entry-interrupt) #f))
-
- (let* ((entry-lbl (bbs-new-lbl! *bbs*))
- (body-lbl (bbs-new-lbl! *bbs*))
- (frame (current-frame ret-var-set)))
-
- (bbs-entry-lbl-num-set! *bbs* entry-lbl)
-
- (set! entry-bb
- (make-bb (make-LABEL-PROC entry-lbl 0 0 #f #f frame #f)
- *bbs*))
-
- (bb-put-branch! entry-bb
- (make-JUMP (make-lbl body-lbl) #f #f frame #f))
-
- (set! *bb*
- (make-bb (make-LABEL-SIMP body-lbl frame #f)
- *bbs*))
-
- (let loop1 ((l program))
- (if (not (null? l))
- (let ((node (car l)))
- (if (def? node)
- (let* ((var (def-var node))
- (val (global-val var)))
- (if (and val (prc? val))
- (add-constant-var var
- (make-obj
- (make-proc-obj
- (symbol->string (var-name var)) ; name
- #t ; primitive?
- #f ; code
- (call-pattern val) ; call-pat
- #t ; side-effects?
- '() ; strict-pat
- '(#f))))))) ; type
- (loop1 (cdr l)))))
-
- (let loop2 ((l program))
- (if (null? l)
-
- (let ((ret-opnd (var->opnd ret-var)))
- (seal-bb #t 'RETURN)
- (dealloc-slots nb-slots)
- (bb-put-branch! *bb*
- (make-JUMP ret-opnd #f #f (current-frame (set-empty)) #f)))
-
- (let ((node (car l)))
- (if (def? node)
-
- (begin
- (gen-define (def-var node) (def-val node) info-port)
- (loop2 (cdr l)))
-
- (if (null? (cdr l))
- (gen-node node ret-var-set 'tail)
- (begin
- (gen-node node ret-var-set 'need)
- (loop2 (cdr l))))))))
-
- (let loop ()
- (if (pair? proc-queue)
- (let ((x (car proc-queue)))
- (set! proc-queue (cdr proc-queue))
- (gen-proc (car x) (cadr x) (caddr x) info-port)
- (trace-unindent info-port)
- (loop))))
-
- (if info-port
- (begin
- (newline info-port)
- (newline info-port)))
-
- (bbs-purify! *bbs*)
-
- (let ((proc
- (make-proc-obj
- (string-append "###" module-name) ; name
- #t ; primitive?
- *bbs* ; code
- '(0) ; call-pat
- #t ; side-effects?
- '() ; strict-pat
- '(#f)))) ; type
-
- (set! *bb* '())
- (set! *bbs* '())
- (set! *global-env* '())
-
- (set! proc-tree '())
- (set! proc-queue '())
- (set! constant-vars '())
- (set! known-procs '())
-
- (clear-context)
-
- proc)))
-
- (define *bb* '())
- (define *bbs* '())
- (define *global-env* '())
-
- (define proc-tree '())
- (define proc-queue '())
- (define constant-vars '())
- (define known-procs '())
-
- (define trace-indentation '())
-
- (define (trace-indent info-port)
- (set! trace-indentation (+ trace-indentation 1))
- (if info-port
- (begin
- (newline info-port)
- (let loop ((i trace-indentation))
- (if (> i 0)
- (begin (display " " info-port) (loop (- i 1))))))))
-
- (define (trace-unindent info-port)
- (set! trace-indentation (- trace-indentation 1)))
-
- ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- (define (gen-define var node info-port)
- (if (prc? node)
-
- (let* ((p-bbs *bbs*)
- (p-bb *bb*)
- (p-proc-tree proc-tree)
- (p-proc-queue proc-queue)
- (p-known-procs known-procs)
- (p-context (current-context))
- (bbs (make-bbs))
- (lbl1 (bbs-new-lbl! bbs)) ; arg check entry point
- (lbl2 (bbs-new-lbl! bbs)) ; no arg check entry point
- (context (entry-context node '()))
- (frame (context->frame
- context
- (set-union (free-variables (prc-body node))
- ret-var-set)))
- (bb1 (make-bb
- (make-LABEL-PROC
- lbl1
- (length (prc-parms node))
- (prc-min node)
- (prc-rest node)
- #f
- frame
- (source-comment node))
- bbs))
- (bb2 (make-bb
- (make-LABEL-SIMP
- lbl2
- frame
- (source-comment node))
- bbs)))
-
- (define (do-body)
- (gen-proc node bb2 context info-port)
- (let loop ()
- (if (pair? proc-queue)
- (let ((x (car proc-queue)))
- (set! proc-queue (cdr proc-queue))
- (gen-proc (car x) (cadr x) (caddr x) info-port)
- (trace-unindent info-port)
- (loop))))
- (trace-unindent info-port)
- (bbs-purify! *bbs*))
-
- (context-entry-bb-set! context bb1)
- (bbs-entry-lbl-num-set! bbs lbl1)
- (bb-put-branch! bb1
- (make-JUMP (make-lbl lbl2) #f #f frame (source-comment node)))
- (set! *bbs* bbs)
- (set! proc-tree '())
- (set! proc-queue '())
- (set! known-procs '())
- (if (constant-var? var)
- (let-constant-var var (make-lbl lbl1)
- (lambda ()
- (add-known-proc lbl1 node)
- (do-body)))
- (do-body))
- (set! *bbs* p-bbs)
- (set! *bb* p-bb)
- (set! proc-tree p-proc-tree)
- (set! proc-queue p-proc-queue)
- (set! known-procs p-known-procs)
- (restore-context p-context)
- (let* ((x (assq var constant-vars))
- (proc (if x
- (let ((p (cdr x)))
- (proc-obj-code-set! (obj-val p) bbs)
- p)
- (make-obj
- (make-proc-obj
- (symbol->string (var-name var)) ; name
- #f ; primitive?
- bbs ; code
- (call-pattern node) ; call-pat
- #t ; side-effects?
- '() ; strict-pat
- '(#f)))))) ; type
- (put-copy proc
- (make-glo (var-name var))
- #f
- ret-var-set)))
-
- (put-copy (gen-node node ret-var-set 'need)
- (make-glo (var-name var))
- #f
- ret-var-set)))
-
- (define (call-pattern node)
- (make-pattern (prc-min node) (length (prc-parms node)) (prc-rest node)))
-
- ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ;
- ; Runtime context manipulation (i.e. where the variables are, what registers
- ; are in use, etc.)
-
- ; runtime context description: nb-slots = number of slots presently allocated
- ; for the current frame on the stack, slots = list of variables associated with
- ; each slot (topmost slot first), regs = list of variables contained in each
- ; register, closed = list of variables which are closed with respect to the
- ; current procedure, interrupt = what is the maximum number of PVM instructions
- ; that can be executed before doing an interrupt check and have interrupts been
- ; checked since entry to this procedure, entry-bb = the entry basic block for
- ; the procedure containing this context (must have a label of type PROC).
-
- (define (make-context nb-slots slots regs closed interrupt entry-bb)
- (vector nb-slots slots regs closed interrupt entry-bb))
-
- (define (context-nb-slots x) (vector-ref x 0))
- (define (context-slots x) (vector-ref x 1))
- (define (context-regs x) (vector-ref x 2))
- (define (context-closed x) (vector-ref x 3))
- (define (context-interrupt x) (vector-ref x 4))
- (define (context-entry-bb x) (vector-ref x 5))
- (define (context-entry-bb-set! x y) (vector-set! x 5 y))
-
- (define nb-slots '())
- (define slots '())
- (define regs '())
- (define closed '())
- (define interrupt '())
- (define entry-bb '())
-
- (define (restore-context context)
- (set! nb-slots (context-nb-slots context))
- (set! slots (context-slots context))
- (set! regs (context-regs context))
- (set! closed (context-closed context))
- (set! interrupt (context-interrupt context))
- (set! entry-bb (context-entry-bb context)))
-
- (define (clear-context)
- (restore-context (make-context '() '() '() '() '() '())))
-
- (define (current-context)
- (make-context nb-slots slots regs closed interrupt entry-bb))
-
- (define (current-frame live)
- (make-frame nb-slots slots regs closed live))
-
- (define (context->frame context live)
- (make-frame (context-nb-slots context)
- (context-slots context)
- (context-regs context)
- (context-closed context)
- live))
-
- (define (make-interrupt checked? delta)
- (cons checked? delta))
-
- (define (interrupt-checked? x) (car x))
- (define (interrupt-delta x) (cdr x))
-
- (define (entry-interrupt)
- (make-interrupt #f (- interrupt-period interrupt-head)))
-
- (define (return-interrupt interrupt)
- (let ((delta (interrupt-delta interrupt)))
- (make-interrupt (interrupt-checked? interrupt)
- (+ interrupt-head (max delta interrupt-tail)))))
-
- (define (interrupt-merge interrupt other-interrupt)
- (make-interrupt
- (or (interrupt-checked? interrupt)
- (interrupt-checked? other-interrupt))
- (max (interrupt-delta interrupt)
- (interrupt-delta other-interrupt))))
-
- (define interrupt-period #f) ; Lmax
- (set! interrupt-period 90)
-
- (define interrupt-head #f) ; E
- (set! interrupt-head 15)
-
- (define interrupt-tail #f) ; R
- (set! interrupt-tail 15)
-
- ; (entry-context proc closed) returns the context in existence upon entry to
- ; the procedure `proc'
-
- (define (entry-context proc closed)
-
- (define (empty-vars-list n)
- (if (> n 0)
- (cons empty-var (empty-vars-list (- n 1)))
- '()))
-
- (let* ((parms (prc-parms proc))
- (pc (target.label-info (prc-min proc) (length parms) (prc-rest proc) (not (null? closed))))
- (fs (pcontext-fs pc))
- (slots-list (empty-vars-list fs))
- (regs-list (empty-vars-list target.nb-regs)))
-
- (define (assign-var-to-loc var loc)
- (let ((x (cond ((reg? loc)
- (let ((i (reg-num loc)))
- (if (<= i target.nb-regs)
- (nth-after regs-list i)
- (compiler-internal-error
- "entry-context, reg out of bound in back-end's pcontext"))))
- ((stk? loc)
- (let ((i (stk-num loc)))
- (if (<= i fs)
- (nth-after slots-list (- fs i))
- (compiler-internal-error
- "entry-context, stk out of bound in back-end's pcontext"))))
- (else
- (compiler-internal-error
- "entry-context, loc other than reg or stk in back-end's pcontext")))))
- (if (eq? (car x) empty-var)
- (set-car! x var)
- (compiler-internal-error
- "entry-context, duplicate location in back-end's pcontext"))))
-
- (let loop ((l (pcontext-map pc)))
- (if (not (null? l))
- (let* ((couple (car l))
- (name (car couple))
- (loc (cdr couple)))
- (cond ((eq? name 'return)
- (assign-var-to-loc ret-var loc))
- ((eq? name 'closure-env)
- (assign-var-to-loc closure-env-var loc))
- (else
- (assign-var-to-loc (list-ref parms (- name 1)) loc)))
- (loop (cdr l)))))
-
- (make-context fs slots-list regs-list closed (entry-interrupt) #f)))
-
- (define (get-var opnd)
- (cond ((glo? opnd)
- (env-lookup-global-var *global-env* (glo-name opnd)))
- ((reg? opnd)
- (list-ref regs (reg-num opnd)))
- ((stk? opnd)
- (list-ref slots (- nb-slots (stk-num opnd))))
- (else
- (compiler-internal-error
- "get-var, location must be global, register or stack slot"))))
-
- (define (put-var opnd new)
-
- (define (put-v opnd new)
- (cond ((reg? opnd)
- (set! regs (replace-nth regs (reg-num opnd) new)))
- ((stk? opnd)
- (set! slots (replace-nth slots (- nb-slots (stk-num opnd)) new)))
- (else
- (compiler-internal-error
- "put-var, location must be register or stack slot, for var:"
- (var-name new)))))
-
- (if (eq? new ret-var) ; only keep one copy of return address
- (let ((x (var->opnd ret-var)))
- (and x (put-v x empty-var))))
- (put-v opnd new))
-
- (define (flush-regs)
- (set! regs '()))
-
- (define (push-slot)
- (set! nb-slots (+ nb-slots 1))
- (set! slots (cons empty-var slots)))
-
- (define (dealloc-slots n)
- (set! nb-slots (- nb-slots n))
- (set! slots (nth-after slots n)))
-
- (define (pop-slot)
- (dealloc-slots 1))
-
- (define (replace-nth l i v)
- (if (null? l)
- (if (= i 0)
- (list v)
- (cons empty-var (replace-nth l (- i 1) v)))
- (if (= i 0)
- (cons v (cdr l))
- (cons (car l) (replace-nth (cdr l) (- i 1) v)))))
-
- (define (live-vars live)
- (if (not (set-empty? (set-intersection live (list->set closed))))
- (set-adjoin live closure-env-var)
- live))
-
- (define (dead-slots live)
- (let ((live-v (live-vars live)))
- (define (loop s l i)
- (cond ((null? l) (list->set (reverse s)))
- ((set-member? (car l) live-v)
- (loop s (cdr l) (- i 1)))
- (else
- (loop (cons i s) (cdr l) (- i 1)))))
- (loop '() slots nb-slots)))
-
- (define (live-slots live)
- (let ((live-v (live-vars live)))
- (define (loop s l i)
- (cond ((null? l) (list->set (reverse s)))
- ((set-member? (car l) live-v)
- (loop (cons i s) (cdr l) (- i 1)))
- (else
- (loop s (cdr l) (- i 1)))))
- (loop '() slots nb-slots)))
-
- (define (dead-regs live)
- (let ((live-v (live-vars live)))
- (define (loop s l i)
- (cond ((>= i target.nb-regs) (list->set (reverse s)))
- ((null? l)
- (loop (cons i s) l (+ i 1)))
- ((and (set-member? (car l) live-v)
- (not (memq (car l) slots)))
- (loop s (cdr l) (+ i 1)))
- (else
- (loop (cons i s) (cdr l) (+ i 1)))))
- (loop '() regs 0)))
-
- (define (live-regs live)
- (let ((live-v (live-vars live)))
- (define (loop s l i)
- (cond ((null? l) (list->set (reverse s)))
- ((and (set-member? (car l) live-v)
- (not (memq (car l) slots)))
- (loop (cons i s) (cdr l) (+ i 1)))
- (else
- (loop s (cdr l) (+ i 1)))))
- (loop '() regs 0)))
-
- (define (lowest-dead-slot live)
- (make-stk (or (lowest (dead-slots live)) (+ nb-slots 1))))
-
- (define (highest-live-slot live)
- (make-stk (or (highest (live-slots live)) 0)))
-
- (define (lowest-dead-reg live)
- (let ((x (lowest (set-remove (dead-regs live) 0))))
- (if x (make-reg x) #f)))
-
- (define (highest-dead-reg live)
- (let ((x (highest (dead-regs live))))
- (if x (make-reg x) #f)))
-
- (define (highest set) ; return highest number in the set
- (if (set-empty? set) #f (apply max (set->list set))))
-
- (define (lowest set) ; return lowest number in the set
- (if (set-empty? set) #f (apply min (set->list set))))
-
- (define (above set n) ; return numbers above n in the set
- (set-keep (lambda (x) (> x n)) set))
-
- (define (below set n) ; return numbers below n in the set
- (set-keep (lambda (x) (< x n)) set))
-
- (define (var->opnd var)
- (let ((x (assq var constant-vars)))
- (if x
- (cdr x)
- (if (global? var)
- (make-glo (var-name var))
- (let ((n (pos-in-list var regs)))
- (if n
- (make-reg n)
- (let ((n (pos-in-list var slots)))
- (if n
- (make-stk (- nb-slots n))
- (let ((n (pos-in-list var closed)))
- (if n
- (make-clo (var->opnd closure-env-var) (+ n 1))
- (compiler-internal-error
- "var->opnd, variable is not accessible:" (var-name var))))))))))))
-
- (define (source-comment node)
- (let ((x (make-comment)))
- (comment-put! x 'SOURCE (node-source node))
- x))
-
- ;------------------------------------------------------------------------------
-
- (define (add-constant-var var opnd)
- (set! constant-vars (cons (cons var opnd) constant-vars)))
-
- (define (let-constant-var var opnd thunk)
- (let* ((x (assq var constant-vars))
- (temp (cdr x)))
- (set-cdr! x opnd)
- (thunk)
- (set-cdr! x temp)))
-
- (define (constant-var? var)
- (assq var constant-vars))
-
- (define (not-constant-var? var)
- (not (constant-var? var)))
-
- (define (add-known-proc label proc)
- (set! known-procs (cons (cons label proc) known-procs)))
-
- ;------------------------------------------------------------------------------
- ;
- ; generate code for a procedure
-
- (define (gen-proc proc bb context info-port)
- (trace-indent info-port)
- (if info-port
- (if (prc-name proc)
- (display (prc-name proc) info-port)
- (display "\"unknown\"" info-port)))
- (let ((lbl (bb-lbl-num bb))
- (live (set-union (free-variables (prc-body proc)) ret-var-set)))
- (set! *bb* bb)
- (restore-context context)
- (gen-node (prc-body proc) ret-var-set 'tail)))
-
- (define (schedule-gen-proc proc closed-list)
- (let* ((lbl1 (bbs-new-lbl! *bbs*)) ; arg check entry point
- (lbl2 (bbs-new-lbl! *bbs*)) ; no arg check entry point
- (context (entry-context proc closed-list))
- (frame (context->frame
- context
- (set-union (free-variables (prc-body proc))
- ret-var-set)))
- (bb1 (make-bb
- (make-LABEL-PROC
- lbl1
- (length (prc-parms proc))
- (prc-min proc)
- (prc-rest proc)
- (not (null? closed-list))
- frame
- (source-comment proc))
- *bbs*))
- (bb2 (make-bb
- (make-LABEL-SIMP
- lbl2
- frame
- (source-comment proc))
- *bbs*)))
- (context-entry-bb-set! context bb1)
- (bb-put-branch! bb1
- (make-JUMP (make-lbl lbl2) #f #f frame (source-comment proc)))
- (set! proc-tree (cons (cons lbl1 (bb-lbl-num entry-bb)) proc-tree))
- (set! proc-queue (cons (list proc bb2 context) proc-queue))
- (make-lbl lbl1)))
-
- ;------------------------------------------------------------------------------
- ;
- ; generate code for an expression
-
- (define (gen-node node live why)
-
- (cond ((cst? node)
- (gen-return
- (make-obj (cst-val node))
- why
- node))
-
- ((ref? node)
- (let* ((var (ref-var node))
- (name (var-name var)))
- (gen-return
- (cond ((eq? why 'side)
- (make-obj undef-object))
- ((global? var)
- (let ((prim (target.prim-info* name (node-decl node))))
- (if prim (make-obj prim) (var->opnd var))))
- (else
- (var->opnd var)))
- why
- node)))
-
- ((set? node)
- (let* ((src (gen-node (set-val node)
- (set-adjoin live (set-var node))
- 'keep))
- (dst (var->opnd (set-var node))))
- (put-copy src dst #f live)
- (gen-return (make-obj undef-object) why node)))
-
- ((def? node)
- (compiler-internal-error
- "gen-node, 'def' node not at root of parse tree"))
-
- ((tst? node)
- (gen-tst node live why))
-
- ((conj? node)
- (gen-conj/disj node live why))
-
- ((disj? node)
- (gen-conj/disj node live why))
-
- ((prc? node)
- (let* ((closed (not-constant-closed-vars node))
- (closed-list (set->list closed))
- (proc-lbl (schedule-gen-proc node closed-list)))
- (let ((opnd
- (if (null? closed-list)
- (begin
- (add-known-proc (lbl-num proc-lbl) node)
- proc-lbl)
- (begin
- (dealloc-slots (- nb-slots
- (stk-num (highest-live-slot
- (set-union closed live)))))
- (push-slot)
- (let ((slot (make-stk nb-slots))
- (var (make-temp-var 'closure)))
- (put-var slot var)
- (bb-put-non-branch! *bb*
- (make-MAKE_CLOSURES
- (list (make-closure-parms
- slot
- (lbl-num proc-lbl)
- (map var->opnd closed-list)))
- (current-frame (set-adjoin live var))
- (source-comment node)))
- slot)))))
- (gen-return opnd why node))))
-
- ((app? node)
- (gen-call node live why))
-
- ((fut? node)
- (gen-fut node live why))
-
- (else
- (compiler-internal-error
- "gen-node, unknown parse tree node type:" node))))
-
- (define (gen-return opnd why node)
- (cond ((eq? why 'tail)
- (let ((var (make-temp-var 'result)))
- (put-copy opnd target.proc-result var ret-var-set)
- (let ((ret-opnd (var->opnd ret-var)))
- (seal-bb (intr-checks? (node-decl node)) 'RETURN)
- (dealloc-slots nb-slots)
- (bb-put-branch! *bb*
- (make-JUMP ret-opnd
- #f
- #f
- (current-frame (set-singleton var))
- (source-comment node))))))
- (else
- opnd)))
-
- (define (not-constant-closed-vars val)
- (set-keep not-constant-var? (free-variables val)))
-
- ;------------------------------------------------------------------------------
- ;
- ; generate code for a conditional
-
- (define (predicate node live cont)
-
- (define (cont* true-lbl false-lbl)
- (cont false-lbl true-lbl))
-
- (define (generic-true-test)
- (predicate-test node live **NOT-proc-obj '0 (list node) cont*))
-
- (cond ((or (conj? node) (disj? node))
- (predicate-conj/disj node live cont))
-
- ((app? node)
- (let ((proc (node->proc (app-oper node))))
- (if proc
- (let ((spec (specialize-for-call proc (node-decl node))))
- (if (and (proc-obj-test spec)
- (nb-args-conforms? (length (app-args node))
- (proc-obj-call-pat spec)))
-
- (if (eq? spec **NOT-proc-obj)
- (predicate (car (app-args node)) live cont*)
- (predicate-test node live spec
- (proc-obj-strict-pat proc)
- (app-args node)
- cont))
-
- (generic-true-test)))
-
- (generic-true-test))))
-
- (else
- (generic-true-test))))
-
- (define (predicate-conj/disj node live cont)
- (let* ((pre (if (conj? node) (conj-pre node) (disj-pre node)))
- (alt (if (conj? node) (conj-alt node) (disj-alt node)))
- (alt-live (set-union live (free-variables alt))))
-
- (predicate pre alt-live
-
- (lambda (true-lbl false-lbl)
-
- (let ((pre-context (current-context)))
-
- (set! *bb* (make-bb
- (make-LABEL-SIMP
- (if (conj? node) true-lbl false-lbl)
- (current-frame alt-live)
- (source-comment pre))
- *bbs*))
-
- (predicate alt live
-
- (lambda (true-lbl2 false-lbl2)
-
- (let ((alt-context (current-context)))
-
- (restore-context pre-context)
-
- (set! *bb* (make-bb
- (make-LABEL-SIMP
- (if (conj? node) false-lbl true-lbl)
- (current-frame live)
- (source-comment alt))
- *bbs*))
-
- (merge-contexts-and-seal-bb
- alt-context
- live
- (intr-checks? (node-decl node))
- 'INTERNAL)
-
- (bb-put-branch! *bb*
- (make-JUMP
- (make-lbl (if (conj? node) false-lbl2 true-lbl2))
- #f
- #f
- (current-frame live)
- (source-comment node)))
-
- (cont true-lbl2 false-lbl2)))))))))
-
- (define (predicate-test node live test strict-pat args cont)
- (let loop ((args* args) (liv live) (vars* '()))
- (if (not (null? args*))
-
- (let* ((needed (vals-live-vars liv (cdr args*)))
- (var
- (save-var (gen-node (car args*) needed 'need)
- (make-temp-var 'predicate)
- needed)))
- (loop (cdr args*) (set-adjoin liv var) (cons var vars*)))
-
- (let* ((true-lbl (bbs-new-lbl! *bbs*))
- (false-lbl (bbs-new-lbl! *bbs*)))
-
- (seal-bb (intr-checks? (node-decl node)) 'INTERNAL)
-
- (bb-put-branch! *bb*
- (make-COND
- test
- (flag-pot-fut (map var->opnd (reverse vars*))
- (lambda (i) (pattern-member? i strict-pat))
- (node-decl node))
- true-lbl
- false-lbl
- #f
- (current-frame live)
- (source-comment node)))
-
- (cont true-lbl false-lbl)))))
-
- (define (gen-tst node live why)
-
- (let ((pre (tst-pre node))
- (con (tst-con node))
- (alt (tst-alt node)))
-
- (predicate pre (set-union live (free-variables con) (free-variables alt))
-
- (lambda (true-lbl false-lbl)
-
- (let ((pre-context (current-context))
- (true-bb (make-bb
- (make-LABEL-SIMP
- true-lbl
- (current-frame (set-union live (free-variables con)))
- (source-comment con))
- *bbs*))
- (false-bb (make-bb
- (make-LABEL-SIMP
- false-lbl
- (current-frame (set-union live (free-variables alt)))
- (source-comment alt))
- *bbs*)))
-
- (set! *bb* true-bb)
-
- (let ((con-opnd (gen-node con live why)))
-
- (if (eq? why 'tail)
-
- (begin
- (restore-context pre-context)
- (set! *bb* false-bb)
- (gen-node alt live why))
-
- (let* ((result-var (make-temp-var 'result))
- (live-after (set-adjoin live result-var)))
-
- (save-opnd-to-reg con-opnd
- target.proc-result
- result-var
- live)
-
- (let ((con-context (current-context))
- (con-bb *bb*))
- (restore-context pre-context)
- (set! *bb* false-bb)
-
- (save-opnd-to-reg (gen-node alt live why)
- target.proc-result
- result-var
- live)
-
- (let ((next-lbl (bbs-new-lbl! *bbs*))
- (alt-bb *bb*))
-
- (if (> (context-nb-slots con-context) nb-slots)
- (begin
- (seal-bb (intr-checks? (node-decl node)) 'INTERNAL)
- (let ((alt-context (current-context)))
- (restore-context con-context)
- (set! *bb* con-bb)
- (merge-contexts-and-seal-bb
- alt-context
- live-after
- (intr-checks? (node-decl node))
- 'INTERNAL)))
- (let ((alt-context (current-context)))
- (restore-context con-context)
- (set! *bb* con-bb)
- (seal-bb (intr-checks? (node-decl node)) 'INTERNAL)
- (let ((con-context* (current-context)))
- (restore-context alt-context)
- (set! *bb* alt-bb)
- (merge-contexts-and-seal-bb
- con-context*
- live-after
- (intr-checks? (node-decl node))
- 'INTERNAL))))
-
- (let ((frame (current-frame live-after)))
-
- (bb-put-branch! con-bb
- (make-JUMP
- (make-lbl next-lbl)
- #f
- #f
- frame
- (source-comment node)))
-
- (bb-put-branch! alt-bb
- (make-JUMP
- (make-lbl next-lbl)
- #f
- #f
- frame
- (source-comment node)))
-
- (set! *bb* (make-bb
- (make-LABEL-SIMP
- next-lbl
- frame
- (source-comment node))
- *bbs*))
-
- target.proc-result)))))))))))
-
- (define (nb-args-conforms? n call-pat)
- (pattern-member? n call-pat))
-
- ; 'merge-contexts-and-seal-bb' generates code to transform the current
- ; context (i.e. reg and stack values and frame size) to 'other-context' only
- ; considering the variables in 'live'.
-
- (define (merge-contexts-and-seal-bb other-context live checks? where)
- (let ((live-v (live-vars live))
- (other-nb-slots (context-nb-slots other-context))
- (other-regs (context-regs other-context))
- (other-slots (context-slots other-context))
- (other-interrupt (context-interrupt other-context))
- (other-entry-bb (context-entry-bb other-context)))
-
- (let loop1 ((i (- target.nb-regs 1)))
- (if (>= i 0)
-
- (let ((other-var (reg->var other-regs i))
- (var (reg->var regs i)))
- (if (and (not (eq? var other-var)) ; if var not already there and
- (set-member? other-var live-v)) ; must keep other-var somewhere
- (let ((r (make-reg i)))
- (put-var r empty-var)
- (if (not (or (not (set-member? var live-v))
- (memq var regs)
- (memq var slots)))
- (let ((top (make-stk (+ nb-slots 1))))
- (put-copy r top var live-v)))
- (put-copy (var->opnd other-var) r other-var live-v)))
- (loop1 (- i 1)))))
-
- (let loop2 ((i 1))
- (if (<= i other-nb-slots)
-
- (let ((other-var (stk->var other-slots i))
- (var (stk->var slots i)))
- (if (and (not (eq? var other-var)) ; if var not already there and
- (set-member? other-var live-v)) ; must keep other-var somewhere
- (let ((s (make-stk i)))
- (if (<= i nb-slots) (put-var s empty-var))
- (if (not (or (not (set-member? var live-v))
- (memq var regs)
- (memq var slots)))
- (let ((top (make-stk (+ nb-slots 1))))
- (put-copy s top var live-v)))
- (put-copy (var->opnd other-var) s other-var live-v))
- (if (> i nb-slots)
- (let ((top (make-stk (+ nb-slots 1))))
- (put-copy (make-obj undef-object) top empty-var live-v))))
- (loop2 (+ i 1)))))
-
- (dealloc-slots (- nb-slots other-nb-slots))
-
- (let loop3 ((i (- target.nb-regs 1)))
- (if (>= i 0)
-
- (let ((other-var (reg->var other-regs i))
- (var (reg->var regs i)))
- (if (not (eq? var other-var))
- (put-var (make-reg i) empty-var))
- (loop3 (- i 1)))))
-
- (let loop4 ((i 1))
- (if (<= i other-nb-slots)
-
- (let ((other-var (stk->var other-slots i))
- (var (stk->var slots i)))
- (if (not (eq? var other-var))
- (put-var (make-stk i) empty-var))
- (loop4 (+ i 1)))))
-
- (seal-bb checks? where)
-
- (set! interrupt (interrupt-merge interrupt other-interrupt))
-
- (if (not (eq? entry-bb other-entry-bb))
- (compiler-internal-error
- "merge-contexts-and-seal-bb, entry-bb's do not agree"))))
-
- (define (seal-bb checks? where)
-
- (define (last-pair l)
- (if (pair? (cdr l)) (last-pair (cdr l)) l))
-
- (define (intr-check-at split-point)
- (let loop ((i 0) (l1 (bb-non-branch-instrs *bb*)) (l2 '()))
- (if (< i split-point)
- (loop (+ i 1) (cdr l1) (cons (car l1) l2))
- (let* ((label-instr (bb-label-instr *bb*))
- (non-branch-instrs1 (reverse l2))
- (non-branch-instrs2 l1)
- (frame (pvm-instr-frame
- (car (last-pair (cons label-instr
- non-branch-instrs1)))))
- (prec-bb (make-bb label-instr *bbs*))
- (new-lbl (bbs-new-lbl! *bbs*)))
- (bb-non-branch-instrs-set! prec-bb non-branch-instrs1)
- (bb-put-branch! prec-bb
- (make-JUMP (make-lbl new-lbl) #f #t frame #f))
- (bb-label-instr-set! *bb* (make-LABEL-SIMP new-lbl frame #f))
- (bb-non-branch-instrs-set! *bb* non-branch-instrs2)
- (set! interrupt (make-interrupt #t 0))))))
-
- (define (intr-check-at-end)
- (intr-check-at (length (bb-non-branch-instrs *bb*))))
-
- (define (impose-intr-check-constraints)
- (let ((n (+ (length (bb-non-branch-instrs *bb*)) 1))
- (delta (interrupt-delta interrupt)))
- (if (> (+ delta n) interrupt-period)
- (begin
- (intr-check-at (max (- interrupt-period delta) 0))
- (impose-intr-check-constraints)))))
-
- (if checks? (impose-intr-check-constraints))
-
- (let* ((n (+ (length (bb-non-branch-instrs *bb*)) 1))
- (delta (+ (interrupt-delta interrupt) n))
- (checked? (interrupt-checked? interrupt)))
- (if (and checks?
- (case where
- ((CALL)
- (> delta (- interrupt-period interrupt-head)))
- ((TAIL-CALL)
- (> delta interrupt-tail))
- ((RETURN)
- (and checked? (> delta (+ interrupt-head interrupt-tail))))
- ((INTERNAL)
- #f)
- (else
- (compiler-internal-error "seal-bb, unknown 'where':" where))))
- (intr-check-at-end)
- (set! interrupt (make-interrupt checked? delta)))))
-
- (define (reg->var regs i)
- (cond ((null? regs)
- '())
- ((> i 0)
- (reg->var (cdr regs) (- i 1)))
- (else
- (car regs))))
-
- (define (stk->var slots i)
- (let ((j (- (length slots) i)))
- (if (< j 0)
- '()
- (list-ref slots j))))
-
- ;------------------------------------------------------------------------------
- ;
- ; generate code for a conjunction or disjunction
-
- (define (gen-conj/disj node live why)
-
- (let ((pre (if (conj? node) (conj-pre node) (disj-pre node)))
- (alt (if (conj? node) (conj-alt node) (disj-alt node))))
-
- (let ((needed (set-union live (free-variables alt)))
- (bool? (boolean-value? pre))
- (predicate-var (make-temp-var 'predicate)))
-
- (define (general-predicate node live cont)
- (let* ((con-lbl (bbs-new-lbl! *bbs*))
- (alt-lbl (bbs-new-lbl! *bbs*)))
-
- (save-opnd-to-reg (gen-node pre live 'need)
- target.proc-result
- predicate-var
- live)
-
- (seal-bb (intr-checks? (node-decl node)) 'INTERNAL)
-
- (bb-put-branch! *bb*
- (make-COND
- **NOT-proc-obj
- (flag-pot-fut (list target.proc-result)
- (lambda (i) #t)
- (node-decl node))
- alt-lbl
- con-lbl
- #f
- (current-frame (set-adjoin live predicate-var))
- (source-comment node)))
-
- (cont con-lbl alt-lbl)))
-
- (define (alternative con-lbl alt-lbl)
- (let* ((pre-context (current-context))
- (result-var (make-temp-var 'result))
- (con-live (if bool? live (set-adjoin live predicate-var)))
- (alt-live (set-union live (free-variables alt)))
- (con-bb (make-bb
- (make-LABEL-SIMP
- con-lbl
- (current-frame con-live)
- (source-comment node))
- *bbs*))
- (alt-bb (make-bb
- (make-LABEL-SIMP
- alt-lbl
- (current-frame alt-live)
- (source-comment alt))
- *bbs*)))
-
- (if bool?
- (begin
- (set! *bb* con-bb)
- (save-opnd-to-reg (make-obj (if (conj? node) false-object #t))
- target.proc-result
- result-var
- live))
- (put-var (var->opnd predicate-var) result-var))
-
- (let ((con-context (current-context)))
-
- (set! *bb* alt-bb)
-
- (restore-context pre-context)
-
- (let ((alt-opnd (gen-node alt live why)))
-
- (if (eq? why 'tail)
-
- (begin
- (restore-context con-context)
- (set! *bb* con-bb)
- (let ((ret-opnd (var->opnd ret-var))
- (result-set (set-singleton result-var)))
- (seal-bb (intr-checks? (node-decl node)) 'RETURN)
- (dealloc-slots nb-slots)
- (bb-put-branch! *bb*
- (make-JUMP ret-opnd
- #f
- #f
- (current-frame result-set)
- (source-comment node)))))
-
- (let ((alt-context* (current-context))
- (alt-bb* *bb*))
-
- (restore-context con-context)
- (set! *bb* con-bb)
- (seal-bb (intr-checks? (node-decl node)) 'INTERNAL)
-
- (let ((con-context* (current-context))
- (next-lbl (bbs-new-lbl! *bbs*)))
-
- (restore-context alt-context*)
- (set! *bb* alt-bb*)
-
- (save-opnd-to-reg alt-opnd
- target.proc-result
- result-var
- live)
-
- (merge-contexts-and-seal-bb
- con-context*
- (set-adjoin live result-var)
- (intr-checks? (node-decl node))
- 'INTERNAL)
-
- (let ((frame (current-frame (set-adjoin live result-var))))
-
- (bb-put-branch! *bb*
- (make-JUMP
- (make-lbl next-lbl)
- #f
- #f
- frame
- (source-comment node)))
-
- (bb-put-branch! con-bb
- (make-JUMP
- (make-lbl next-lbl)
- #f
- #f
- frame
- (source-comment node)))
-
- (set! *bb* (make-bb
- (make-LABEL-SIMP
- next-lbl
- frame
- (source-comment node))
- *bbs*))
-
- target.proc-result))))))))
-
- ((if bool? predicate general-predicate) pre needed
- (lambda (true-lbl false-lbl)
- (if (conj? node)
- (alternative false-lbl true-lbl)
- (alternative true-lbl false-lbl)))))))
-
- ;------------------------------------------------------------------------------
- ;
- ; generate code for a procedure call
-
- (define (gen-call node live why)
- (let* ((oper (app-oper node))
- (args (app-args node))
- (nb-args (length args)))
-
- (if (and (prc? oper) ; applying a lambda-expr is like a 'let' or 'letrec'
- (not (prc-rest oper))
- (= (length (prc-parms oper)) nb-args))
-
- (gen-let (prc-parms oper) args (prc-body oper) live why)
-
- (if (inlinable-app? node)
-
- (let ((eval-order (arg-eval-order #f args))
- (vars (map (lambda (x) (cons x #f)) args)))
-
- (let loop ((l eval-order) (liv live))
- (if (not (null? l))
-
- (let* ((needed (vals-live-vars liv (map car (cdr l))))
- (arg (car (car l)))
- (pos (cdr (car l)))
- (var
- (save-var (gen-node arg needed 'need)
- (make-temp-var pos)
- needed)))
- (set-cdr! (assq arg vars) var)
- (loop (cdr l) (set-adjoin liv var)))
-
- (let ((loc (if (eq? why 'side)
- (make-reg 0)
- (or (lowest-dead-reg live) (lowest-dead-slot live)))))
-
- (if (and (stk? loc) (> (stk-num loc) nb-slots)) (push-slot))
-
- (let* ((args (map var->opnd (map cdr vars)))
- (var (make-temp-var 'result))
- (proc (node->proc oper))
- (strict-pat (proc-obj-strict-pat proc)))
-
- (if (not (eq? why 'side)) (put-var loc var))
-
- (bb-put-non-branch! *bb*
- (make-APPLY (specialize-for-call proc (node-decl node))
- (flag-pot-fut
- args
- (lambda (i) (pattern-member? i strict-pat))
- (node-decl node))
- (if (eq? why 'side) #f loc)
- (current-frame (if (eq? why 'side) live (set-adjoin live var)))
- (source-comment node)))
-
- (gen-return loc why node))))))
-
- (let* ((calling-local-proc?
- (and (ref? oper)
- (let ((opnd (var->opnd (ref-var oper))))
- (and (lbl? opnd)
- (let ((x (assq (lbl-num opnd) known-procs)))
- (and x
- (let ((proc (cdr x)))
- (and (not (prc-rest proc))
- (= (prc-min proc) nb-args)
- (= (length (prc-parms proc)) nb-args)
- (lbl-num opnd)))))))))
- (jstate
- (get-jump-state
- args
- (if calling-local-proc?
- (target.label-info nb-args nb-args #f #f)
- (target.jump-info nb-args))))
- (in-stk (jump-state-in-stk jstate))
- (in-reg (jump-state-in-reg jstate))
- (eval-order (arg-eval-order (if calling-local-proc? #f oper) in-reg))
- (live-after (if (eq? why 'tail) (set-remove live ret-var) live))
- (live-for-regs (args-live-vars live eval-order))
- (return-lbl (if (eq? why 'tail) #f (bbs-new-lbl! *bbs*))))
-
- ; save regs on stack if they contain values needed after the call
- (save-regs (live-regs live-after)
- (stk-live-vars live-for-regs in-stk why))
-
- (let ((frame-start (stk-num (highest-live-slot live-after))))
-
- (let loop1 ((l in-stk) (liv live-after) (i (+ frame-start 1)))
- (if (not (null? l))
-
- ; ==== FIRST: evaluate arguments that go onto stack
-
- (let ((arg (car l))
- (slot (make-stk i))
- (needed (set-union (stk-live-vars liv (cdr l) why)
- live-for-regs)))
- (if arg
- (let ((var (if (and (eq? arg 'return) (eq? why 'tail))
- ret-var
- (make-temp-var (- frame-start i)))))
- (save-opnd-to-stk (if (eq? arg 'return)
- (if (eq? why 'tail)
- (var->opnd ret-var)
- (make-lbl return-lbl))
- (gen-node arg needed 'need))
- slot
- var
- needed)
- (loop1 (cdr l) (set-adjoin liv var) (+ i 1)))
- (begin
- (if (> i nb-slots)
- (put-copy (make-obj undef-object) slot empty-var liv))
- (loop1 (cdr l) liv (+ i 1)))))
-
- (let loop2 ((l eval-order) (liv liv) (reg-map '()) (oper-var '()))
- (if (not (null? l))
-
- ; ==== SECOND: evaluate operator and args that go in registers
-
- (let* ((arg (car (car l)))
- (pos (cdr (car l)))
- (needed (args-live-vars liv (cdr l)))
- (var (if (and (eq? arg 'return) (eq? why 'tail))
- ret-var
- (make-temp-var pos)))
- (opnd (if (eq? arg 'return)
- (if (eq? why 'tail)
- (var->opnd ret-var)
- (make-lbl return-lbl))
- (gen-node arg needed 'need))))
-
- (if (eq? pos 'operator)
-
- ; operator
-
- (if (and (ref? arg)
- (not (or (obj? opnd) (lbl? opnd))))
- (loop2 (cdr l)
- (set-adjoin liv (ref-var arg))
- reg-map
- (ref-var arg))
- (begin
- (save-arg opnd var needed)
- (loop2 (cdr l)
- (set-adjoin liv var)
- reg-map
- var)))
-
- ; return address or argument
-
- (let ((reg (make-reg pos)))
-
- (if (all-args-trivial? (cdr l))
- (save-opnd-to-reg opnd reg var needed)
- (save-in-slot opnd var needed))
-
- (loop2 (cdr l)
- (set-adjoin liv var)
- (cons (cons pos var) reg-map)
- oper-var))))
-
- (let loop3 ((i (- target.nb-regs 1)))
- (if (>= i 0)
-
- ; ==== THIRD: reload spilled registers
-
- (let ((couple (assq i reg-map)))
- (if couple
- (let ((var (cdr couple)))
- (if (not (eq? (reg->var regs i) var))
- (save-opnd-to-reg (var->opnd var) (make-reg i) var liv))))
- (loop3 (- i 1)))
-
- ; ==== FOURTH: jump to procedure
-
- (let ((opnd (if calling-local-proc?
- (make-lbl (+ calling-local-proc? 1))
- (var->opnd oper-var))))
-
- (seal-bb (intr-checks? (node-decl node))
- (if return-lbl 'CALL 'TAIL-CALL))
-
- (dealloc-slots (- nb-slots (+ frame-start (length in-stk))))
-
- (bb-put-branch! *bb*
- (make-JUMP
- (car (flag-pot-fut (list opnd)
- (lambda (i) #t)
- (node-decl node)))
- (if calling-local-proc? #f nb-args)
- #f
- (current-frame liv)
- (source-comment node)))
-
- ; ==== FIFTH: put return label if there is one
-
- (let ((result-var (make-temp-var 'result)))
-
- (dealloc-slots (- nb-slots frame-start))
- (flush-regs)
- (put-var target.proc-result result-var)
-
- (if return-lbl
- (begin
- (set! interrupt (return-interrupt interrupt))
- (set! *bb*
- (make-bb
- (make-LABEL-RETURN
- return-lbl
- #f
- (current-frame (set-adjoin live result-var))
- (source-comment node))
- *bbs*))))
-
- target.proc-result))))))))))))))
-
- (define (contained-reg/slot opnd)
- (cond ((reg? opnd)
- opnd)
- ((stk? opnd)
- opnd)
- ((clo? opnd)
- (contained-reg/slot (clo-base opnd)))
- (else
- #f)))
-
- (define (opnd-needed opnd needed)
- (let ((x (contained-reg/slot opnd)))
- (if x
- (set-adjoin needed (get-var x))
- needed)))
-
- (define (save-opnd opnd live)
- (let ((slot (lowest-dead-slot live)))
- (put-copy opnd slot (get-var opnd) live)))
-
- (define (save-regs regs live)
- (for-each (lambda (i) (save-opnd (make-reg i) live)) (set->list regs)))
-
- (define (save-opnd-to-reg opnd reg var live)
- (if (set-member? (reg-num reg) (live-regs live))
- (save-opnd reg (opnd-needed opnd live)))
- (put-copy opnd reg var live))
-
- (define (save-opnd-to-stk opnd stk var live)
- (if (set-member? (stk-num stk) (live-slots live))
- (save-opnd stk (opnd-needed opnd live)))
- (put-copy opnd stk var live))
-
- (define (all-args-trivial? l)
- (if (null? l)
- #t
- (let ((arg (car (car l))))
- (or (eq? arg 'return)
- (and (trivial? arg)
- (all-args-trivial? (cdr l)))))))
-
- (define (every-trivial? l)
- (or (null? l)
- (and (trivial? (car l))
- (every-trivial? (cdr l)))))
-
- (define (trivial? node)
- (or (cst? node)
- (ref? node)
- (and (set? node) (trivial? (set-val node)))
- (and (inlinable-app? node) (every-trivial? (app-args node)))))
-
- (define (inlinable-app? node)
- (if (app? node)
- (let ((proc (node->proc (app-oper node))))
- (and proc
- (let ((spec (specialize-for-call proc (node-decl node))))
- (and (proc-obj-inlinable spec)
- (nb-args-conforms? (length (app-args node))
- (proc-obj-call-pat spec))))))
- #f))
-
- (define (boolean-value? node)
- (or (and (conj? node)
- (boolean-value? (conj-pre node))
- (boolean-value? (conj-alt node)))
- (and (disj? node)
- (boolean-value? (disj-pre node))
- (boolean-value? (disj-alt node)))
- (boolean-app? node)))
-
- (define (boolean-app? node)
- (if (app? node)
- (let ((proc (node->proc (app-oper node))))
- (if proc
- (eq? (type-name (proc-obj-type proc)) 'BOOLEAN)
- #f))
- #f))
-
- (define (node->proc node)
- (cond ((cst? node)
- (if (proc-obj? (cst-val node))
- (cst-val node)
- #f))
- ((ref? node)
- (if (global? (ref-var node))
- (target.prim-info* (var-name (ref-var node)) (node-decl node))
- #f))
- (else
- #f)))
-
- (define (specialize-for-call proc decl)
- ((proc-obj-specialize proc) decl))
-
- (define (flag-pot-fut opnds strict? decl)
-
- (define (flag opnds i)
- (if (pair? opnds)
- (let ((opnd (car opnds)))
- (cons (if (and (not (or (lbl? opnd) (obj? opnd))) (strict? i))
- (put-pot-fut opnd)
- opnd)
- (flag (cdr opnds) (+ i 1))))
- '()))
-
- (if (autotouch? decl)
- (flag opnds 0)
- opnds))
-
- (define (get-jump-state args pc)
-
- (define (empty-node-list n)
- (if (> n 0)
- (cons #f (empty-node-list (- n 1)))
- '()))
-
- (let* ((fs (pcontext-fs pc))
- (slots-list (empty-node-list fs))
- (regs-list (empty-node-list target.nb-regs)))
-
- (define (assign-node-to-loc var loc)
- (let ((x (cond ((reg? loc)
- (let ((i (reg-num loc)))
- (if (<= i target.nb-regs)
- (nth-after regs-list i)
- (compiler-internal-error
- "jump-state, reg out of bound in back-end's pcontext"))))
- ((stk? loc)
- (let ((i (stk-num loc)))
- (if (<= i fs)
- (nth-after slots-list (- i 1))
- (compiler-internal-error
- "jump-state, stk out of bound in back-end's pcontext"))))
- (else
- (compiler-internal-error
- "jump-state, loc other than reg or stk in back-end's pcontext")))))
- (if (not (car x))
- (set-car! x var)
- (compiler-internal-error
- "jump-state, duplicate location in back-end's pcontext"))))
-
- (let loop ((l (pcontext-map pc)))
- (if (not (null? l))
- (let* ((couple (car l))
- (name (car couple))
- (loc (cdr couple)))
- (cond ((eq? name 'return)
- (assign-node-to-loc 'return loc))
- (else
- (assign-node-to-loc (list-ref args (- name 1)) loc)))
- (loop (cdr l)))))
-
- (vector slots-list regs-list)))
-
- (define (jump-state-in-stk x) (vector-ref x 0))
-
- (define (jump-state-in-reg x) (vector-ref x 1))
-
- (define (arg-eval-order oper nodes)
-
- (define (loop nodes pos part1 part2)
-
- (cond ((null? nodes)
- (let ((p1 (reverse part1))
- (p2 (free-vars-order part2)))
- (cond ((not oper)
- (append p1 p2))
- ((trivial? oper)
- (append p1 p2 (list (cons oper 'operator))))
- (else
- (append (cons (cons oper 'operator) p1) p2)))))
-
- ((not (car nodes))
- (loop (cdr nodes)
- (+ pos 1)
- part1
- part2))
-
- ((or (eq? (car nodes) 'return)
- (trivial? (car nodes)))
- (loop (cdr nodes)
- (+ pos 1)
- part1
- (cons (cons (car nodes) pos) part2)))
-
- (else
- (loop (cdr nodes)
- (+ pos 1)
- (cons (cons (car nodes) pos) part1)
- part2))))
-
- (loop nodes 0 '() '()))
-
- (define (free-vars-order l)
- (let ((bins '())
- (ordered-args '()))
-
- (define (free-v x)
- (if (eq? x 'return)
- (set-empty)
- (free-variables x)))
-
- (define (add-to-bin! x)
- (let ((y (assq x bins)))
- (if y
- (set-cdr! y (+ (cdr y) 1))
- (set! bins (cons (cons x 1) bins)))))
-
- (define (payoff-if-removed node)
- (let ((x (free-v node)))
- (let loop ((l (set->list x)) (r 0))
- (if (null? l)
- r
- (let ((y (cdr (assq (car l) bins))))
- (loop (cdr l) (+ r (quotient 1000 (* y y))))))))) ; heuristic
-
- (define (remove-free-vars! x)
- (let loop ((l (set->list x)))
- (if (not (null? l))
- (let ((y (assq (car l) bins)))
- (set-cdr! y (- (cdr y) 1))
- (loop (cdr l))))))
-
- (define (find-max-payoff l thunk)
- (if (null? l)
- (thunk '() -1)
- (find-max-payoff (cdr l)
- (lambda (best-arg best-payoff)
- (let ((payoff (payoff-if-removed (car (car l)))))
- (if (>= payoff best-payoff)
- (thunk (car l) payoff)
- (thunk best-arg best-payoff)))))))
-
- (define (remove x l)
- (cond ((null? l) '())
- ((eq? x (car l)) (cdr l))
- (else (cons (car l) (remove x (cdr l))))))
-
- (for-each (lambda (x)
- (for-each add-to-bin! (set->list (free-v (car x)))))
- l)
-
- (let loop ((args l) (ordered-args '()))
- (if (null? args)
- (reverse ordered-args)
- (find-max-payoff args
- (lambda (best-arg best-payoff)
- (remove-free-vars! (free-v (car best-arg)))
- (loop (remove best-arg args) (cons best-arg ordered-args))))))))
-
- (define (args-live-vars live order)
- (cond ((null? order)
- live)
- ((eq? (car (car order)) 'return)
- (args-live-vars (set-adjoin live ret-var)
- (cdr order)))
- (else
- (args-live-vars (set-union live (free-variables (car (car order))))
- (cdr order)))))
-
- (define (stk-live-vars live slots why)
- (cond ((null? slots)
- live)
- ((not (car slots))
- (stk-live-vars live
- (cdr slots)
- why))
- ((eq? (car slots) 'return)
- (stk-live-vars (if (eq? why 'tail) (set-adjoin live ret-var) live)
- (cdr slots)
- why))
- (else
- (stk-live-vars (set-union live (free-variables (car slots)))
- (cdr slots)
- why))))
-
-
- ;------------------------------------------------------------------------------
- ;
- ; generate code for a 'let' or 'letrec'
-
- (define (gen-let vars vals node live why)
- (let ((var-val-map (pair-up vars vals))
- (var-set (list->set vars))
- (all-live (set-union live
- (free-variables node)
- (apply set-union (map free-variables vals)))))
-
- (define (var->val var) (cdr (assq var var-val-map)))
-
- (define (proc-var? var) (prc? (var->val var)))
-
- (define (closed-vars var const-proc-vars)
- (set-difference (not-constant-closed-vars (var->val var))
- const-proc-vars))
-
- (define (no-closed-vars? var const-proc-vars)
- (set-empty? (closed-vars var const-proc-vars)))
-
- (define (closed-vars? var const-proc-vars)
- (not (no-closed-vars? var const-proc-vars)))
-
- (define (compute-const-proc-vars proc-vars)
- (let loop1 ((const-proc-vars proc-vars))
- (let ((new-const-proc-vars
- (set-keep (lambda (x) (no-closed-vars? x const-proc-vars))
- const-proc-vars)))
- (if (not (set-equal? new-const-proc-vars const-proc-vars))
- (loop1 new-const-proc-vars)
- const-proc-vars))))
-
- (let* ((proc-vars (set-keep proc-var? var-set))
- (const-proc-vars (compute-const-proc-vars proc-vars))
- (clo-vars (set-keep (lambda (x) (closed-vars? x const-proc-vars))
- proc-vars))
- (clo-vars-list (set->list clo-vars)))
-
- (for-each
- (lambda (proc-var)
- (let ((label (schedule-gen-proc (var->val proc-var) '())))
- (add-known-proc (lbl-num label) (var->val proc-var))
- (add-constant-var proc-var label)))
- (set->list const-proc-vars))
-
- (let ((non-clo-vars-list
- (set->list
- (set-keep (lambda (var)
- (and (not (set-member? var const-proc-vars))
- (not (set-member? var clo-vars))))
- vars)))
- (liv (set-union live
- (apply
- set-union
- (map (lambda (x) (closed-vars x const-proc-vars))
- clo-vars-list))
- (free-variables node))))
-
- (let loop2 ((vars* non-clo-vars-list))
- (if (not (null? vars*))
- (let* ((var (car vars*))
- (val (var->val var))
- (needed (vals-live-vars liv
- (map var->val (cdr vars*)))))
- (if (var-useless? var)
- (gen-node val needed 'side)
- (save-val (gen-node val needed 'need) var needed))
- (loop2 (cdr vars*)))))
-
- (if (pair? clo-vars-list)
- (begin
-
- (dealloc-slots
- (- nb-slots (stk-num (highest-live-slot liv))))
-
- (let loop3 ((l clo-vars-list))
- (if (not (null? l))
- (begin
- (push-slot)
- (let ((var (car l))
- (slot (make-stk nb-slots)))
- (put-var slot var)
- (loop3 (cdr l))))))
-
- (bb-put-non-branch! *bb*
- (make-MAKE_CLOSURES
- (map (lambda (var)
- (let ((closed-list
- (set->list (closed-vars var const-proc-vars))))
- (if (null? closed-list)
- (compiler-internal-error
- "gen-let, no closed variables:" (var-name var))
- (make-closure-parms
- (var->opnd var)
- (lbl-num (schedule-gen-proc
- (var->val var)
- closed-list))
- (map var->opnd closed-list)))))
- clo-vars-list)
- (current-frame live)
- (source-comment node)))))
-
- (gen-node node live why)))))
-
- (define (save-arg opnd var live)
- (if (glo? opnd)
- (add-constant-var var opnd)
- (save-val opnd var live)))
-
- (define (save-val opnd var live)
- (cond ((or (obj? opnd) (lbl? opnd))
- (add-constant-var var opnd))
- ((and (reg? opnd)
- (not (set-member? (reg-num opnd) (live-regs live))))
- (put-var opnd var))
- ((and (stk? opnd)
- (not (set-member? (stk-num opnd) (live-slots live))))
- (put-var opnd var))
- (else
- (save-in-slot opnd var live))))
-
- (define (save-in-slot opnd var live)
- (let ((slot (lowest-dead-slot live)))
- (put-copy opnd slot var live)))
-
- (define (save-var opnd var live)
- (cond ((or (obj? opnd) (lbl? opnd))
- (add-constant-var var opnd)
- var)
- ((or (glo? opnd) (reg? opnd) (stk? opnd))
- (get-var opnd))
- (else
- (let ((dest (or (highest-dead-reg live) (lowest-dead-slot live))))
- (put-copy opnd dest var live)
- var))))
-
- (define (put-copy opnd loc var live)
- (if (and (stk? loc) (> (stk-num loc) nb-slots)) (push-slot))
- (if var (put-var loc var))
- (if (not (eq? opnd loc))
- (bb-put-non-branch! *bb*
- (make-COPY opnd loc (current-frame (if var (set-adjoin live var) live)) #f))))
-
- (define (var-useless? var)
- (and (set-empty? (var-refs var))
- (set-empty? (var-sets var))))
-
- (define (vals-live-vars live vals)
- (if (null? vals)
- live
- (vals-live-vars (set-union live (free-variables (car vals)))
- (cdr vals))))
-
- ;------------------------------------------------------------------------------
- ;
- ; generate code for a future
-
- (define (gen-fut node live why)
- (let* ((val (fut-val node))
- (clo-vars (not-constant-closed-vars val))
- (clo-vars-list (set->list clo-vars))
- (ret-var* (make-temp-var 0))
- (live-after live)
- (live-starting-task (set-adjoin (set-union live-after clo-vars)
- ret-var*))
- (task-lbl (bbs-new-lbl! *bbs*))
- (return-lbl (bbs-new-lbl! *bbs*)))
-
- ; save regs on stack if they contain values needed after the future
- (save-regs (live-regs live-after)
- live-starting-task)
-
- (let ((frame-start (stk-num (highest-live-slot live-after))))
-
- ; move return address to where task expects it
- (save-opnd-to-reg (make-lbl return-lbl)
- target.task-return
- ret-var*
- (set-remove live-starting-task ret-var*))
-
- ; save variables that the task needs (that are not in regs)
- (let loop1 ((l clo-vars-list) (i 0))
- (if (null? l)
- (dealloc-slots (- nb-slots (+ frame-start i)))
- (let ((var (car l))
- (rest (cdr l)))
- (if (memq var regs)
- (loop1 rest i)
- (let loop2 ((j (- target.nb-regs 1)))
- (if (>= j 0)
- (if (or (>= j (length regs))
- (not (set-member? (list-ref regs j) live-starting-task)))
- (let ((reg (make-reg j)))
- (put-copy (var->opnd var) reg var live-starting-task)
- (loop1 rest i))
- (loop2 (- j 1)))
- (let ((slot (make-stk (+ frame-start (+ i 1))))
- (needed (list->set rest)))
- (if (and (or (> (stk-num slot) nb-slots)
- (not (memq (list-ref slots (- nb-slots (stk-num slot))) regs)))
- (set-member? (stk-num slot) (live-slots needed)))
- (save-opnd slot live-starting-task))
- (put-copy (var->opnd var) slot var live-starting-task)
- (loop1 rest (+ i 1)))))))))
-
- (seal-bb (intr-checks? (node-decl node)) 'CALL)
-
- (bb-put-branch! *bb*
- (make-JUMP (make-lbl task-lbl)
- #f
- #f
- (current-frame live-starting-task)
- (source-comment node)))
-
- (let ((method
- (futures-method (node-decl node)))
- (task-context
- (make-context (- nb-slots frame-start)
- (reverse (nth-after (reverse slots) frame-start))
- (cons ret-var (cdr regs))
- '()
- interrupt
- entry-bb))
- (return-context
- (make-context frame-start
- (nth-after slots (- nb-slots frame-start))
- '()
- closed
- (return-interrupt interrupt)
- entry-bb)))
-
- (restore-context task-context)
- (set! *bb* (make-bb
- (make-LABEL-TASK
- task-lbl
- method
- (current-frame live-starting-task)
- (source-comment node))
- *bbs*))
-
- (gen-node val ret-var-set 'tail)
-
- (let ((result-var (make-temp-var 'future)))
- (restore-context return-context)
- (put-var target.proc-result result-var)
-
- (set! *bb* (make-bb
- (make-LABEL-RETURN
- return-lbl
- method
- (current-frame (set-adjoin live result-var))
- (source-comment node))
- *bbs*))
-
- (gen-return target.proc-result why node))))))
-
- ;------------------------------------------------------------------------------
-